using System.Reflection;
using Gateway.Common.Entity;
using Gateway.Domain.EFCore.QueryFilters;
using Gateway.Infrastructure.Provider.Operator;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Sharding;
using ShardingCore.Sharding.Abstractions;

namespace Gateway.Domain.EFCore;

public class ShareCoreDbContext : AbstractShardingDbContext,IShardingTableDbContext
{
    private  IOperatorProvider _operatorProvider;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="options"></param>
    public ShareCoreDbContext(DbContextOptions options) : base(options)
    {
      
    }
    /// <summary>
    /// configure 配置
    /// </summary>
    /// <param name="optionsBuilder"></param>
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var assembly = Assembly.GetAssembly(typeof(ShareCoreDbContext))!;
        modelBuilder.ApplyConfigurationsFromAssembly(assembly);
        // 省略其它无关的代码

        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            if (typeof(EntityWithOperatorStatusBase).IsAssignableFrom(entityType.ClrType))
            {
                // 添加删除的记录标记的筛选
                entityType.AddDeletedQueryFilter();
            }
        }

        base.OnModelCreating(modelBuilder);
    }

    public void SetOperator(IOperatorProvider operatorProvider)
    {
        _operatorProvider = operatorProvider;
    }
    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
    {
        BeforeSaveChange(ChangeTracker.Entries<AggregateRootEntityBase>().ToList());
        return base.SaveChangesAsync(cancellationToken);
    }

    /// <summary>
    /// 写入数据库前,设置实体审计、租户信息
    /// </summary>
    /// <param name="entities"></param>
    private void BeforeSaveChange(IReadOnlyCollection<EntityEntry<AggregateRootEntityBase>> entities)
    {
        if (!entities.Any()) return;
        var @operator = _operatorProvider?.GetOperator();
        if(@operator==null) return;
        foreach (var e in entities)
        {
            switch (e.State)
            {
                case EntityState.Added:
                    if (string.IsNullOrWhiteSpace(e.Entity.CreatedBy))
                        e.Entity.SetCreate(@operator.OperatorId, @operator.OperatorName);
                    break;
                case EntityState.Modified:
                    e.Entity.SetModifier(@operator.OperatorId, @operator.OperatorName);
                    break;
            }
        }
    }
    public IRouteTail RouteTail { get; set; }
}